﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using FileDuplicateRemover.Core;
using Useful.MVP2;
using Useful.Sys;

namespace FileDuplicateRemover.Gui
{
    public class DuplicateListViewPresenter : BaseListPresenter<DuplicateListViewModel, IDuplicateListView, FileEntityRepository>
    {
        private enum ActionType { CreateList, Delete, CreateTree, CalcHash }

        private class ActionArgs
        {
            public ActionType ActionType;
        }

        private BackgroundWorker _backgroundWorker = null;

        public DuplicateListViewPresenter(IDuplicateListView view, FileEntityRepository repository, IPresenterImpl presenterImpl)
            : base(view, repository, presenterImpl)
        {
            //base.Model = repository.Create();

            _backgroundWorker = new BackgroundWorker();
            _backgroundWorker.WorkerSupportsCancellation = true;
            _backgroundWorker.WorkerReportsProgress = true;

            _backgroundWorker.DoWork += _backgroundWorker_DoWork;
            _backgroundWorker.ProgressChanged += _backgroundWorker_ProgressChanged;
            _backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;

            View.CollapseClicked += View_CollapseClicked;
            View.CheckItemClicked += View_CheckItemClicked;
            View.BeforeDirectorySelected += View_BeforeDirectorySelected;
            View.AfterDirectorySelected += View_AfterDirectorySelected;
            View.CheckNotFirstClicked += ViewCheckNotFirstClicked;
            View.UnCheckAllClicked += ViewUnCheckAllClicked;
            View.DeleteCheckedClicked += View_DeleteCheckedClicked;
            View.FormClosingEvent += View_FormClosingEvent;
            View.BreakProgressClicked += View_BreakProgressClicked;
            View.FileNameClicked += View_FileNameClicked;
            View.FormShown += View_FormShown;
            View.HideEmptyClicked += View_HideEmptyClicked;
            View.TimerProgressTick += View_TimerProgressTick;
            View.CreateDirectoryTreeClicked += View_CreateDirectoryTreeClicked;
            View.CalcHashClicked += View_CalcHashClicked;
            View.LoadViewModelClicked += View_LoadViewModelClicked;
            View.SaveViewModelClicked += View_SaveViewModelClicked;
        }

        private void View_SaveViewModelClicked(object sender, StringEventArgscs e)
        {
            try
            {
                if (e.Value != null)
                {
                    Model.SelectedDataFileFullName = e.Value;
                    View.SelectedDataFileFullName = Model.SelectedDataFileFullName;

                    Repository.SaveViewModel(Model.SelectedDataFileFullName, Model);

                    ShowWarring("OK");
                }
            }
            catch (Exception ex)
            {
                HandleException("View_SaveViewModelClicked", ex);
            }
        }

        private void View_LoadViewModelClicked(object sender, StringEventArgscs e)
        {
            try
            {
                if (e.Value != null)
                {
                    Model.SelectedDataFileFullName = e.Value;
                    View.SelectedDataFileFullName = Model.SelectedDataFileFullName;

                    Model = Repository.LoadViewModel(Model.SelectedDataFileFullName);

                    ShowWarring("OK");

                    //AfterCreateListComplite();

                    View.EnableView = !String.IsNullOrEmpty(Model.RootDirectoryFullName) && Model.RootDirectoryEntity != null; ;
                    View.InfoText = Model.InfoText;
                }
            }
            catch (Exception ex)
            {
                HandleException("View_LoadViewModelClicked", ex);
            }
        }

        private void View_CalcHashClicked(object sender, EventArgs e)
        {
            try
            {
                CheckRootDirectoryEntity();

                Model.CurrentProgressVal = 0;

                View.MaximumProgressValue = (int)Model.RootDirectoryEntity.TotalEntityCount;
                View.ActionHeader = "Вычисление хешей";
                SetProgressControlsEnable(true);

                View.SetActionProgesssCurrentVal(Model.CurrentProgressVal);

                _backgroundWorker.RunWorkerAsync(new ActionArgs() { ActionType = ActionType.CalcHash });

                View.EnableTimerProgress = true;
            }
            catch (Exception ex)
            {
                HandleException("View_CalcHashClicked", ex);
            }
        }

        private void View_CreateDirectoryTreeClicked(object sender, EventArgs e)
        {
            try
            {
                CreateDirectoryTree();
            }
            catch (Exception ex)
            {
                HandleException("View_CreateDirectoryTreeClicked", ex);
            }
        }

        private void View_FileNameClicked(object sender, EventArgs e)
        {
            try
            {
                GridItem item = (GridItem)View.GetCurrentItem();

                SystemHelper.ShowFile(item.Name);
            }
            catch (Win32Exception ex)
            {
                HandleException("Нет программы для отображения элемента", ex);
            }
            catch (Exception ex)
            {
                HandleException("View_FileNameClicked", ex);
            }
        }

        private void View_BreakProgressClicked(object sender, EventArgs e)
        {
            try
            {
                _backgroundWorker.CancelAsync();
            }
            catch (Exception ex)
            {
                HandleException("View_BreakProgressClicked", ex);
            }
        }

        private void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                if (e.Error == null)
                {
                    ActionArgs aa = (ActionArgs)e.Result;

                    View.EnableTimerProgress = false;

                    string str;
                    switch (aa.ActionType)
                    {
                        case ActionType.CreateList:
                            str = "Поиск одинаковых элементов - завершено";

                            AfterCreateListComplite();
                            break;
                        case ActionType.Delete:
                            str = "Удаление завершено";
                            break;
                        case ActionType.CreateTree:
                            str = "Построение дерева завершено";

                            View.EnableView = !String.IsNullOrEmpty(Model.RootDirectoryFullName) && Model.RootDirectoryEntity != null; ;
                            View.InfoText = Model.InfoText;
                            break;
                        case ActionType.CalcHash:
                            str = "Вычисление хэшей - завершено";

                            Model.IsHashCalc = true;

                            View.EnableView = !String.IsNullOrEmpty(Model.RootDirectoryFullName) && Model.RootDirectoryEntity != null; ;
                            View.InfoText = Model.InfoText;
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                            break;
                    }

                    View.SetActionProgesssCurrentVal(View.MaximumProgressValue);

                    ShowWarring(str);

                    SetProgressControlsEnable(false);
                }
                else
                {
                    HandleException("_backgroundWorker_RunWorkerCompleted: e.Error:", e.Error);
                    View.EnableTimerProgress = false;
                    SetProgressControlsEnable(false);
                }
            }
            catch (Exception ex)
            {
                HandleException("_backgroundWorker_RunWorkerCompleted", ex);
            }
        }

        private void AfterCreateListComplite()
        {
            // Список для грида

            List<GridItem> list = new List<GridItem>(Model.DuplicateEntityList.Count() * 2);

            foreach (DuplicateEntityDescription ded in Model.DuplicateEntityList)
            {
                list.Add(new GridItem(ded, ded.SomeEntity, true));

                foreach (BaseEntity be in ded)
                {
                    if (be != ded.SomeEntity)
                    {
                        list.Add(new GridItem(ded, be, false));
                    }
                }
            }

            GridItemBindingList sbList = new GridItemBindingList(list);

            Model.GridList = sbList;

            View.GroupBy("ID");
            View.ListDataSource = Model.GridList;

            View.EnableWorkWithGrid = Model.GridList != null && Model.GridList.Count > 1;
            View.EnableDeleteChecked = Model.GridList != null && Model.GridList.Count > 1 && Model.AllowDelete;

            View.InfoText = Model.InfoText;
        }

        private void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                //View.InfoText = Model.InfoText;
                //View.SetActionProgesssCurrentVal(e.ProgressPercentage);
                Model.CurrentProgressVal = e.ProgressPercentage;
            }
            catch (Exception ex)
            {
                HandleException("_backgroundWorker_ProgressChanged", ex);
            }
        }

        private void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            //try
            //{
                ActionArgs aa = (ActionArgs) e.Argument;

                switch (aa.ActionType)
                {
                    case ActionType.CalcHash:
                        CheckRootDirectoryEntity();

                        CalcHash();
                        break;
                    case ActionType.CreateList:
                        CheckRootDirectoryEntity();

                        CreateDuplicateList();
                        break;
                    case ActionType.Delete:
                        if (Model.GridList == null)
                            throw new Exception("Таблица директорий ещё не построена");

                        DeleteCheckedCore();
                        break;
                    case ActionType.CreateTree:
                        if (String.IsNullOrEmpty(Model.RootDirectoryFullName))
                            throw new Exception("Не задана корневая папка");

                        CreateDirectoryTreeCore();
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                        break;
                }

                e.Result = aa;
            //}
            //catch (Exception ex)
            //{
            //    HandleException("_backgroundWorker_DoWork", ex);
            //}
        }

        private void CheckRootDirectoryEntity()
        {
            if (Model.RootDirectoryEntity == null)
            {
                throw new Exception("Дерево директорий ещё не построено");
            }
        }

        private void CreateDuplicateList()
        {
            // Список дубликатов
            Model.DuplicateEntityList = Repository.GetDuplicateEntityDescriptionList(Model.RootDirectoryEntity, NotifyCreateList);
        }

        private void CreateDirectoryTreeCore()
        {
            // Построение дерева
            Model.RootDirectoryEntity = Repository.GetDirectoryEntity(Model.RootDirectoryFullName, NotifyCreateList);
        }

        private void CalcHash()
        {
            // Вычисление хэшей
            Repository.CalcHash(Model.RootDirectoryEntity, NotifyCreateList);
        }

        private bool NotifyCreateList(int val)
        {
            _backgroundWorker.ReportProgress(val);
            //System.Threading.Thread.Sleep(100);

            return _backgroundWorker.CancellationPending;
        }

        private void DeleteCheckedCore()
        {
            int cur = 0;

            foreach (GridItem item in Model.GridList)
            {
                if (_backgroundWorker.CancellationPending)
                    break;

                if (item.Checked)
                {
                    DeleteGridItem(item);

                    item.Checked = !item.IsDeleted;

                    cur++;
                    _backgroundWorker.ReportProgress(cur);                    
                }
            }
        }

        private void View_FormClosingEvent(object sender, System.Windows.Forms.FormClosingEventArgs e)
        {
            try
            {
                if (Model.IsProcessAction)
                {
                    ShowWarring("Дождитесь звершения или прервите процесс");

                    e.Cancel = true;
                }
            }
            catch (Exception ex)
            {
                HandleException("View_FormClosingEvent", ex);                
            }            
        }

        private void View_DeleteCheckedClicked(object sender, EventArgs e)
        {
            try
            {
                if (Model.AllowDelete)
                {
                    int maxCount = Model.GridList.Count(i => i.Checked);

                    if (maxCount > 0)
                    {
                        if (ShowQuestion("Вы действительно ходите удалить элементы?"))
                        {
                            Model.CurrentProgressVal = 0;

                            View.MaximumProgressValue = maxCount;
                            View.SetActionProgesssCurrentVal(Model.CurrentProgressVal);
                            View.ActionHeader = "Удаление";

                            SetProgressControlsEnable(true);

                            _backgroundWorker.RunWorkerAsync(new ActionArgs() {ActionType = ActionType.Delete});

                            View.EnableTimerProgress = true;
                        }
                    }
                    else
                        ShowWarring("Необходимо выбрать элементы");
                }
            }
            catch (Exception ex)
            {
                HandleException("View_DeleteCheckedClicked", ex);

                SetProgressControlsEnable(false);
            }
        }

        private void ViewCheckNotFirstClicked(object sender, EventArgs e)
        {
            CheckUnCheckFirst(true);
        }

        private void ViewUnCheckAllClicked(object sender, EventArgs e)
        {
            CheckUnCheckAll(false);
        }

        private void CheckUnCheckFirst(bool isCheck)
        {
            try
            {
                foreach (GridItem item in Model.GridList)
                {
                    if (!item.IsFirst && !item.IsDeleted)
                    {
                        item.Checked = isCheck;
                    }
                }

                View.InfoText = Model.InfoText;
            }
            catch (Exception ex)
            {
                HandleException("CheckUnCheckFirst", ex);
            }
        }

        private void CheckUnCheckAll(bool isCheck)
        {
            try
            {
                foreach (GridItem item in Model.GridList)
                {
                    item.Checked = isCheck;
                }

                View.InfoText = Model.InfoText;
            }
            catch (Exception ex)
            {
                HandleException("CheckUnCheckAll", ex);
            }
        }

        private void View_BeforeDirectorySelected(object sender, EventArgs e)
        {
            try
            {
                View.SelectedRootDirectory = Model.RootDirectoryFullName;
            }
            catch (Exception ex)
            {
                HandleException("View_BeforeDirectorySelected", ex);
            }
        }

        private void View_AfterDirectorySelected(object sender, EventArgs e)
        {
            try
            {
                Model.RootDirectoryFullName = View.SelectedRootDirectory;
                Model.RootDirectoryEntity = null;
                View.EnableCreateTree = !String.IsNullOrEmpty(Model.RootDirectoryFullName);
                View.EnableView = !String.IsNullOrEmpty(Model.RootDirectoryFullName) && Model.RootDirectoryEntity != null; ;

                //CreateDirectoryTree();
            }
            catch (Exception ex)
            {
                HandleException("View_AfterDirectorySelected", ex);
            }
        }

        private void View_CheckItemClicked(object sender, EventArgs e)
        {
            try
            {
                View.InfoText = Model.InfoText;
            }
            catch (Exception ex)
            {
                HandleException("View_CheckItemClicked", ex);
            }
        }

        private void View_CollapseClicked(object sender, EventArgs e)
        {
            try
            {
                Model.IsCollapsed = !Model.IsCollapsed;
                View.Collapse(Model.IsCollapsed);
            }
            catch (Exception ex)
            {
                HandleException("View_CollapseClicked", ex);
            }
        }

        protected override void OnRefreshClicked()
        {
            CheckRootDirectoryEntity();

            Model.CurrentProgressVal = 0;

            View.MaximumProgressValue = (int)Model.RootDirectoryEntity.TotalEntityCount + 300;
            View.ActionHeader = "Поиск";
            SetProgressControlsEnable(true);

            View.SetActionProgesssCurrentVal(Model.CurrentProgressVal);

            _backgroundWorker.RunWorkerAsync(new ActionArgs() {ActionType = ActionType.CreateList});

            View.EnableTimerProgress = true;
        }

        protected override void OnAddClicked()
        {
        }

        protected override void OnEditClicked(object item)
        {
        }

        protected override void OnDeleteClicked(object item)
        {
            try
            {
                GridItem gridItem = (GridItem) item;

                DeleteGridItem(gridItem);
                gridItem.Checked = false;
            }
            catch (Exception ex)
            {

                HandleException("OnDeleteClicked", ex);
            }
        }

        private void DeleteGridItem(GridItem gridItem)
        {
            try
            {
                if (gridItem.IsDirectory)
                {
                    Repository.DeleteDirectoryEntity(gridItem.Entity as DirectoryEntity);
                }
                else
                {
                    Repository.DeleteFileEntity(gridItem.Entity as FileEntity);
                }

                gridItem.IsDeleted = true;
                gridItem.Result = "OK";
            }
            catch(Exception ex)
            {
                gridItem.IsDeleted = false;
                gridItem.Result = ex.Message;
            }
        }

        protected override void OnCurrentItemPositionChanged(object item)
        {
        }

        protected override bool ValidateFilters()
        {
            bool res = true;

            if (String.IsNullOrEmpty(Model.RootDirectoryFullName))
            {
                res = false;
                ShowWarring("Необходимо выбрать директорию");
            }

            return res;
        }

        protected override void GetFilterFromView()
        {
        }

        protected override void OnViewClose()
        {
            base.OnViewClose();

            View.Close();
        }

        protected override void OnViewLoad()
        {
            base.OnViewLoad();


            View.SelectedRootDirectory = Model.RootDirectoryFullName;

            View.EnableWorkWithGrid = false;
            View.EnableCreateTree = !String.IsNullOrEmpty(Model.RootDirectoryFullName);
            View.EnableView = !String.IsNullOrEmpty(Model.RootDirectoryFullName) && Model.RootDirectoryEntity != null;
            View.EnableDeleteChecked = false;

            View.EnableActionBreakButton = false;
            View.InfoText = Model.InfoText;

            View.EnableTimerProgress = false;
        }

        private void View_FormShown(object sender, EventArgs e)
        {
            try
            {
                //CreateDirectoryTree();
            }
            catch (Exception ex)
            {
                HandleException("View_FormShown", ex);
            }
        }

        private void CreateDirectoryTree()
        {
            if (!String.IsNullOrEmpty(Model.RootDirectoryFullName))
            {
                // Дерево
                //ShowWaiting(null, "Поиск файлов", () => { Model.RootDirectoryEntity = Repository.GetDirectoryEntity(Model.RootDirectoryFullName); });

                ShowWaiting(null, "Подсчёт числа файлов и папок", () => { Model.TotalDirectoryEntity = Repository.GetTotalEntitiesCount(Model.RootDirectoryFullName); });

                //Model.TotalDirectoryEntity = Repository.GetTotalEntitiesCount(Model.RootDirectoryFullName);

                Model.CurrentProgressVal = 0;

                View.MaximumProgressValue = Model.TotalDirectoryEntity;
                View.ActionHeader = "Построение дерева";
                SetProgressControlsEnable(true);

                View.SetActionProgesssCurrentVal(Model.CurrentProgressVal);

                _backgroundWorker.RunWorkerAsync(new ActionArgs() { ActionType = ActionType.CreateTree });

                View.EnableTimerProgress = true;
            }

            //View.InfoText = Model.InfoText;
        }

        private void View_HideEmptyClicked(object sender, BoolEventArgs e)
        {
            try
            {
                //Model.HideEmpty = View.HideEmpty;
                Model.HideEmpty = e.Value;
                View.HideEmpty = Model.HideEmpty;

                foreach (GridItem item in Model.GridList)
                {
                    if (item.Length == 0)
                        View.RowVisible(item, !Model.HideEmpty);
                }
            }
            catch (Exception ex)
            {
                HandleException("View_HideEmpty", ex);
            }
        }

        private void View_TimerProgressTick(object sender, EventArgs e)
        {
            try
            {
                View.InfoText = Model.InfoText;
                View.SetActionProgesssCurrentVal(Model.CurrentProgressVal);
            }
            catch (Exception ex)
            {
                HandleException("View_TimerProgressTick", ex);
            }
        }

        protected override void OnViewInited(InitListViewEventArgs e)
        {
            Repository = (FileEntityRepository)e.Repository;

            base.Model = Repository.CreateViewModel();

            base.OnViewInited(e);
        }

        private void SetProgressControlsEnable(bool enable)
        {
            Model.IsProcessAction = enable;
            View.EnableActionBreakButton = Model.IsProcessAction;
            View.EnableWorkWithGrid = Model.GridList != null && Model.GridList.Count > 1 && !Model.IsProcessAction;
            View.EnableDeleteChecked = Model.GridList != null && Model.GridList.Count > 1 && Model.AllowDelete && !Model.IsProcessAction;
            View.EnableWorkWithFormButtons = !Model.IsProcessAction;
        }

        private void SetButtonsEnabled()
        {
            View.EnableSelectDirectory = true;

            View.EnableCreateTree = !String.IsNullOrEmpty(Model.RootDirectoryFullName);

            View.EnableCalcHash = Model.RootDirectoryEntity != null;

            View.EnableView = Model.RootDirectoryEntity != null;

            View.EnableWorkWithGrid = Model.GridList != null && Model.GridList.Count > 1;

            View.EnableDeleteChecked = Model.GridList != null && Model.GridList.Count > 1 && Model.AllowDelete;

            View.EnableActionBreakButton = Model.IsProcessAction;

            View.EnableWorkWithFormButtons = false;
        }
    }
}
